1 00:00:00,690 --> 00:00:01,230 All right. 2 00:00:01,230 --> 00:00:05,610 In this lecture, we're going to be scripting the I, Squidward that will randomly roam around the map 3 00:00:05,610 --> 00:00:07,050 and chase our players. 4 00:00:07,050 --> 00:00:12,090 This means we'll have to utilize something called the Pathfinding Service to generate waypoints between 5 00:00:12,090 --> 00:00:14,280 two different positions that our AI can walk to. 6 00:00:14,280 --> 00:00:19,860 If our AI sees a player directly, then our AI can just chase those players without needing to pathfind. 7 00:00:19,890 --> 00:00:24,420 Our AI is also going to need to attack or jump scare any players that it gets close to, and it also 8 00:00:24,420 --> 00:00:29,460 needs to be aware of players that are inside of the lockers or have already escaped out of the basement. 9 00:00:29,460 --> 00:00:34,620 That way those players don't accidentally get jump scared to get started, we're going to go ahead and 10 00:00:34,620 --> 00:00:37,380 open up some module scripts we're going to need to script. 11 00:00:38,200 --> 00:00:42,700 So we can go inside of server script service and open up the module section, and we can go ahead and 12 00:00:42,700 --> 00:00:44,830 open up our game sections, module script. 13 00:00:44,830 --> 00:00:50,050 And we're also going to open our AI Squidward Handler module script as well as the properties module 14 00:00:50,050 --> 00:00:51,730 script for that module script. 15 00:00:52,310 --> 00:00:58,130 And then we're also going to go on to the client, and we're going to open up the camera manipulation 16 00:00:58,130 --> 00:01:02,480 handler as well as the jump scares module script. 17 00:01:03,470 --> 00:01:05,420 Now inside of our game sections module script. 18 00:01:05,420 --> 00:01:11,840 Basically, the plan is once we start section two of our game and the players go through that beginning 19 00:01:11,840 --> 00:01:12,890 cut scene. 20 00:01:12,890 --> 00:01:17,840 After we've set everything up and we're waiting for them to open up that door in the basement, what 21 00:01:17,840 --> 00:01:23,600 we could do is we could wait like five seconds after the cut scene to give them a little bit of breathing 22 00:01:23,600 --> 00:01:28,130 room, and then we can start our AI, and that's where we would use our AI, Squidward handler. 23 00:01:28,130 --> 00:01:30,530 And we could have a function in there to start the AI. 24 00:01:30,530 --> 00:01:38,690 So real quick we could create a variable up top here, and I'll just call this, uh, Squidward AI. 25 00:01:39,470 --> 00:01:48,560 Handler and will require from server script service dot server dot modules dot Squidward dot I Squidward 26 00:01:48,560 --> 00:01:49,250 handler. 27 00:01:50,150 --> 00:01:55,340 And then we could go back down and we can refer to our Squidward I handler, and we could have a function 28 00:01:55,340 --> 00:01:57,440 in there, like to start our AI. 29 00:01:57,470 --> 00:01:58,490 Something like that. 30 00:01:59,140 --> 00:02:04,090 So inside of our I, Squidward handler, what we could do is we could create the table that will represent 31 00:02:04,090 --> 00:02:05,080 this module script. 32 00:02:05,080 --> 00:02:07,420 We'll just call it I handler. 33 00:02:09,460 --> 00:02:12,700 And we'll make sure to return I handler at the end of our script. 34 00:02:14,340 --> 00:02:19,140 And then inside of here, we can have a function in our AI handler to start our AI. 35 00:02:21,390 --> 00:02:24,390 And we can also have a function to stop our AI. 36 00:02:26,510 --> 00:02:27,530 Now for our I. 37 00:02:27,530 --> 00:02:32,900 What we have to do is we have to have a while loop that constantly loops through and allows the AI to 38 00:02:32,900 --> 00:02:34,310 continue wandering around. 39 00:02:34,310 --> 00:02:38,180 And when the AI sees a player to attack, it will chase after the player. 40 00:02:38,180 --> 00:02:41,990 Otherwise, if it doesn't see any players at all, it'll just keep wandering around our map. 41 00:02:42,440 --> 00:02:47,450 And the way we can do this is that inside of server storage and our other stuff folder, we have two 42 00:02:47,450 --> 00:02:51,320 different folders, one called Squidward spawns and one called Squidward Rock points. 43 00:02:51,320 --> 00:02:56,990 And this folder contains a bunch of different points or positions around our map that our Squidward 44 00:02:56,990 --> 00:02:58,430 can pathfind to. 45 00:02:58,460 --> 00:03:03,920 So when our Squidward is wandering around the map, we're going to basically have it spawn at one of 46 00:03:03,920 --> 00:03:07,070 these Squidward spawn points, which are inside of the ceiling. 47 00:03:07,070 --> 00:03:12,590 So above our basement we have like the ceiling area where our Squidward can spawn at, and then he can 48 00:03:12,590 --> 00:03:15,590 fall through different points in the ceiling. 49 00:03:15,770 --> 00:03:20,630 So up here, there's these different pass through parts in the ceiling where our Squidward will spawn 50 00:03:20,630 --> 00:03:25,520 up here inside of the ceiling, and then fall down into the basement and start pathfinding. 51 00:03:25,520 --> 00:03:29,480 After a certain period of time where our Squidward has been pathfinding for a while, but it hasn't 52 00:03:29,480 --> 00:03:30,650 seen any players. 53 00:03:30,650 --> 00:03:36,290 What we can do is we can make our Squidward disappear, and then respawn him and put him at a different 54 00:03:36,290 --> 00:03:41,780 position, or a different Squidward spawn and have him fall out of the ceiling at that area instead. 55 00:03:41,780 --> 00:03:44,960 And then have them continue pathfinding until he sees a player. 56 00:03:45,980 --> 00:03:51,500 Now, because our AI is going to be running in a while loop, that means when we start our AI, we're 57 00:03:51,500 --> 00:03:53,840 going to have to spawn it in a different thread. 58 00:03:53,840 --> 00:04:01,610 So we could have a private function actually, and we could call it like start AI, and we could spawn 59 00:04:01,610 --> 00:04:06,890 this function in a new thread when we call the start AI function from our game sections. 60 00:04:06,890 --> 00:04:09,440 Because again, we don't want to be stuck in a while loop here. 61 00:04:09,440 --> 00:04:14,120 Otherwise we won't be able to do any of this other stuff when the thread of execution is stuck looping 62 00:04:14,120 --> 00:04:15,560 forever inside of here. 63 00:04:16,730 --> 00:04:20,000 So inside of our I, Squidward handler, we're going to need some services. 64 00:04:20,000 --> 00:04:21,200 One is going to be service. 65 00:04:21,200 --> 00:04:22,340 Storage, of course. 66 00:04:24,660 --> 00:04:27,240 We are going to need replicated storage. 67 00:04:29,740 --> 00:04:32,350 We're also going to need the player service. 68 00:04:33,930 --> 00:04:36,390 We'll also need the team service. 69 00:04:37,740 --> 00:04:40,770 And then we're also going to need the pathfinding service. 70 00:04:40,770 --> 00:04:42,330 And I'll just call it pathfinding. 71 00:04:42,330 --> 00:04:44,190 And it's equal to game get service. 72 00:04:44,190 --> 00:04:46,350 Pathfinding service. 73 00:04:47,290 --> 00:04:50,650 From this point, we're going to make a references to a couple events. 74 00:04:50,650 --> 00:04:53,800 One is we're going to make a reference to the game comms event. 75 00:04:54,910 --> 00:04:59,140 So that's unreplicated storage, dot events, dot remotes, dot game communication. 76 00:04:59,140 --> 00:05:02,500 And that means we're going to have to get the game comms enum for this event. 77 00:05:02,500 --> 00:05:08,410 So we'll require from replicated storage dot modules dot enums dot game communication enum. 78 00:05:09,310 --> 00:05:17,140 We're also going to need our update UI event replicated storage, dot events, dot remotes, dot update 79 00:05:17,140 --> 00:05:17,890 guy. 80 00:05:18,370 --> 00:05:21,100 And then we can get the guy actions enum as well. 81 00:05:26,090 --> 00:05:31,400 And we're going to be using this event here to tell the players to display a jump scare on the screen. 82 00:05:31,400 --> 00:05:36,740 And we're also going to be using this as well to tell a players to display the death frame. 83 00:05:36,740 --> 00:05:40,910 So when the players get jump scared after the jump scare is over, we want to tell them that, you know, 84 00:05:40,910 --> 00:05:41,390 they died. 85 00:05:41,390 --> 00:05:44,300 So they fade the died screen, you know, onto their screen. 86 00:05:44,300 --> 00:05:47,300 And then we put them back into the spawn area. 87 00:05:47,300 --> 00:05:50,060 And from that point the players can begin to spectate. 88 00:05:50,060 --> 00:05:58,100 We're also going to need the camera manipulation event so we can call it manipulate cam event, replicated 89 00:05:58,100 --> 00:06:00,980 storage, dot events, dot remotes, dot manipulate camera. 90 00:06:01,930 --> 00:06:05,080 And then we're also going to need the camera manipulation enum. 91 00:06:05,440 --> 00:06:10,270 And we'll acquire from replicated storage dot modules dot enums dot camera manipulation enum. 92 00:06:11,500 --> 00:06:14,350 We'll make a reference to our AI, Squidward itself. 93 00:06:14,560 --> 00:06:15,520 It's very important. 94 00:06:15,520 --> 00:06:19,030 And that's inside of server storage, inside of the other stuff folder. 95 00:06:19,030 --> 00:06:21,850 And we can get our handsome Squidward AI. 96 00:06:22,360 --> 00:06:28,390 We're also going to want the properties for our Squidward so we can call this AI properties, and that's 97 00:06:28,390 --> 00:06:33,190 going to be inside of the script dot properties. 98 00:06:34,170 --> 00:06:38,940 We'll make a reference to the humanoid of our AI so we can call it My Humanoid, and that's equal to 99 00:06:38,940 --> 00:06:40,290 I Squidwards humanoid. 100 00:06:40,290 --> 00:06:44,490 And we're also going to get the root part so we can call it my root part equal to I. 101 00:06:44,520 --> 00:06:46,680 Squidward dot humanoid root part. 102 00:06:47,690 --> 00:06:50,660 We're also going to make a reference to the body of our Squidward. 103 00:06:50,660 --> 00:06:54,290 So that's a Squidward dot body. 104 00:06:54,470 --> 00:06:57,470 And we're also going to make a reference to the Squidward eyes. 105 00:06:57,470 --> 00:07:03,920 So attach to our Squidward if I get him outside of our other stuff folder, let me find them real quick. 106 00:07:04,310 --> 00:07:06,050 Here's our handsome Squidward I. 107 00:07:07,270 --> 00:07:08,740 Put him inside of the workspace. 108 00:07:08,740 --> 00:07:09,850 We'll find him. 109 00:07:10,000 --> 00:07:12,460 As you can see, we have his eyes up here. 110 00:07:12,460 --> 00:07:18,670 And what we're going to use his eyes for is we have a part in here called the raycast part, and we're 111 00:07:18,670 --> 00:07:25,630 just going to fire a ray from that position to try to see if our Squidward is able to see any players. 112 00:07:25,630 --> 00:07:26,290 This way. 113 00:07:26,290 --> 00:07:32,260 It stops our Squidward from chasing or trying to see players that are behind walls and stuff like that. 114 00:07:32,260 --> 00:07:36,970 So we want to make sure that the player is first within range of our Squidward, and we actually want 115 00:07:36,970 --> 00:07:40,450 to make sure that our Squidward can actually see the player as well. 116 00:07:41,090 --> 00:07:45,320 So we'll go ahead and put them back inside of his other stuff folder. 117 00:07:46,920 --> 00:07:48,750 And we'll call this variable eyes. 118 00:07:48,750 --> 00:07:51,810 And that's equal to I, Squidward dot eyeballs. 119 00:07:52,320 --> 00:07:57,120 We're also going to make a reference to all the different walking points, or the points that our Squidward 120 00:07:57,120 --> 00:08:02,340 can pathfind to in the map, so we can call it Walk to Points, and that's instead of server storage. 121 00:08:02,340 --> 00:08:07,320 That other stuff dot Squidward Walk points and we'll get all those children. 122 00:08:07,320 --> 00:08:11,760 And we're also going to want to get all of the different spawn points so we can call it spawn points, 123 00:08:11,940 --> 00:08:13,830 and that's inside of server storage. 124 00:08:13,830 --> 00:08:19,650 Dot other stuff that Squidward spawns, and we'll get all of the children inside of there as well. 125 00:08:19,650 --> 00:08:21,990 We'll also want a random data type. 126 00:08:22,840 --> 00:08:27,310 And then we're also going to want some variables to keep track of some specific stuff. 127 00:08:27,310 --> 00:08:32,560 So for example, we want to be able to have our Squidward create footstep sounds. 128 00:08:32,560 --> 00:08:37,270 That way our players know or can listen for when our Squidward is nearby. 129 00:08:37,270 --> 00:08:42,640 So I'll have to set up the footsteps for him, and we only need to do it once so we can have a variable 130 00:08:42,640 --> 00:08:45,520 we could call it is footstep Setup. 131 00:08:45,520 --> 00:08:48,400 To keep track of whether or not we have set up the footsteps or not. 132 00:08:48,670 --> 00:08:52,810 We also need a variable to keep track of whether or not our AI is active. 133 00:08:52,810 --> 00:08:56,080 So we could call it active and we'll set this to false by default. 134 00:08:56,080 --> 00:08:58,660 So when we start our AI, we'll set this to true. 135 00:08:58,660 --> 00:09:01,120 And then when we stop our AI we'll set this to false. 136 00:09:01,120 --> 00:09:04,780 And our while loop is going to constantly check whether or not we are active. 137 00:09:04,780 --> 00:09:06,220 If we're not active, then we'll stop. 138 00:09:06,220 --> 00:09:11,110 You know the AI, but if we are active, then we will continue wandering around the map and looking 139 00:09:11,110 --> 00:09:12,010 for players. 140 00:09:12,580 --> 00:09:17,770 We also need a variable to keep track of whether or not our Squidward can attack or jumpscare players, 141 00:09:17,770 --> 00:09:19,810 and we'll set this to true by default. 142 00:09:20,310 --> 00:09:23,100 So when our Squidward can attack, this will be true. 143 00:09:23,100 --> 00:09:26,040 And then we'll set it to false for a little bit of a cooldown. 144 00:09:26,040 --> 00:09:30,000 So that way our AI can't attack every 0.5 seconds or whatever. 145 00:09:30,610 --> 00:09:36,670 And then we all need a variable to keep track of the amount of wandering iterations. 146 00:09:36,670 --> 00:09:42,370 So each time our Squidward path finds around the basement, every time he hits a pathfinding point, 147 00:09:42,370 --> 00:09:44,050 we're going to plus one. 148 00:09:44,050 --> 00:09:48,670 Add that to his wandering iterations, and then he's going to go wander to a different point. 149 00:09:48,670 --> 00:09:54,700 We'll add plus one to the wandering iterations, and this is to keep track of how long our Squidward 150 00:09:54,700 --> 00:09:56,200 has been wandering for. 151 00:09:56,410 --> 00:10:01,150 So if our Squidward has wandered to multiple different points, let's say it gets above five. 152 00:10:01,150 --> 00:10:02,470 Then we're going to be like, huh? 153 00:10:02,500 --> 00:10:06,820 This Squidward hasn't seen any players, and he's been wandering to five different points. 154 00:10:06,820 --> 00:10:12,550 Maybe we should respawn him and let him pathfind in a different area of our basement, so we can call 155 00:10:12,550 --> 00:10:14,890 this variable Wandering iterations. 156 00:10:14,890 --> 00:10:16,870 And we'll set this to zero by default. 157 00:10:17,140 --> 00:10:22,240 And then we can also keep track of all the different points that our AI has already visited, so we 158 00:10:22,240 --> 00:10:25,600 can call this points already visited. 159 00:10:26,130 --> 00:10:27,780 And this will just be equal to a table. 160 00:10:27,780 --> 00:10:32,400 And that way our Squidward doesn't accidentally visit the same point multiple times in a row. 161 00:10:33,120 --> 00:10:39,450 Okay, so what we want to do when we want to start our AI is first, we want to refer to the humanoid 162 00:10:39,450 --> 00:10:42,450 of our AI and we want to set state enabled. 163 00:10:42,480 --> 00:10:46,560 Enum dot humanoid state type dot falling down equal to false. 164 00:10:46,560 --> 00:10:48,570 This is the absolute first thing we want to do. 165 00:10:48,570 --> 00:10:54,690 And this is because when we spawn our Squidward or UN, anchor him or move him around, there's a chance 166 00:10:54,690 --> 00:10:57,180 he might fall over and we don't want that to happen. 167 00:10:57,180 --> 00:11:04,290 So to stop our Squidward AI from ever being able to fall over or fall down, we set the state enum falling 168 00:11:04,290 --> 00:11:07,080 down to false so he is never able to fall down. 169 00:11:07,440 --> 00:11:13,500 From this point, we need to set our AI Squidward dot parent equal to the workspace so he's visible 170 00:11:13,500 --> 00:11:14,790 to all of our players. 171 00:11:15,400 --> 00:11:22,270 And then we also need to set the root part of the network ownership equal to the server. 172 00:11:22,270 --> 00:11:27,580 This way, no player is able to have network ownership over our Squidward, and that way exploiters 173 00:11:27,580 --> 00:11:30,610 can't do any silly things with our Squidward. 174 00:11:31,200 --> 00:11:35,730 Another thing we will want to make sure real quick is we want to set inside of the humanoid. 175 00:11:35,730 --> 00:11:39,480 We want to set the hip height equal to 2.4 studs. 176 00:11:39,990 --> 00:11:44,310 That way, the feet of our Squidward is about flush to the ground. 177 00:11:44,310 --> 00:11:50,400 So if I go ahead and set the parent of our Squidward equal to the workspace and we go find him here. 178 00:11:50,400 --> 00:11:55,980 Currently, I believe he has a hip height of 2.4 studs, but we can change this. 179 00:11:55,980 --> 00:12:01,890 And if we do something like one, that means when he is unanchored and he goes and walks around, half 180 00:12:01,890 --> 00:12:03,390 of his body is going to be in the floor. 181 00:12:03,390 --> 00:12:07,140 So he's going to be like walking around kind of like this, and this is how he's going to be walking 182 00:12:07,140 --> 00:12:09,240 around, which won't look nice. 183 00:12:09,240 --> 00:12:12,660 So if we set his hip height to 2.4. 184 00:12:13,900 --> 00:12:17,470 Then he's going to be perfectly flushed to the ground about at this height. 185 00:12:17,470 --> 00:12:19,390 And this is how he's going to look when he's walking around. 186 00:12:19,390 --> 00:12:20,680 It looks much nicer. 187 00:12:21,270 --> 00:12:24,030 So we'll put him back inside of server storage. 188 00:12:25,490 --> 00:12:28,340 And we'll make sure to set the hip height at 2.4 studs. 189 00:12:28,670 --> 00:12:34,160 And after we set the hip height, this is where we will want to set up the footsteps for our Squidward. 190 00:12:34,490 --> 00:12:36,710 So what we could do is we could have a function. 191 00:12:36,710 --> 00:12:38,030 And I'll call this function. 192 00:12:38,030 --> 00:12:39,440 Set up footsteps. 193 00:12:41,480 --> 00:12:43,910 And we can call this function down here. 194 00:12:45,400 --> 00:12:49,150 And this is where we will check if we have set up the footsteps or not. 195 00:12:49,150 --> 00:12:53,140 So if is footsteps set up, if that's true, then we're just going to return. 196 00:12:53,860 --> 00:12:58,420 Otherwise from this point is where we would start to set up the footsteps for our Squidward. 197 00:12:58,420 --> 00:13:02,890 And if you don't want our Squidward to have footsteps, then we could create a property inside of our 198 00:13:02,890 --> 00:13:06,460 Squidward to determine whether or not he can have footsteps. 199 00:13:06,850 --> 00:13:12,100 So, for example, in here we could create a key value pair and we can call this has footsteps. 200 00:13:12,370 --> 00:13:14,350 And I want my Squidward to have footsteps. 201 00:13:14,350 --> 00:13:16,060 So I'll set this equal to true. 202 00:13:16,060 --> 00:13:20,050 And what we could do from here is we could refer to our I property. 203 00:13:20,050 --> 00:13:21,730 So if I properties. 204 00:13:21,730 --> 00:13:22,870 Dot has footsteps. 205 00:13:22,870 --> 00:13:28,450 So if we do not want to have footsteps then we'll just return out of this function. 206 00:13:28,840 --> 00:13:32,350 Otherwise what we could do is we could set is footstep setup equal to true. 207 00:13:32,830 --> 00:13:35,470 And what we want to do is we want to create some variables here. 208 00:13:35,470 --> 00:13:37,840 We'll call this variable last material. 209 00:13:37,840 --> 00:13:39,070 We'll set this equal to nil. 210 00:13:39,070 --> 00:13:43,210 We'll also want a variable to check the last position of our Squidward. 211 00:13:43,420 --> 00:13:47,530 And we also want a variable to keep track of the cooldown between footsteps. 212 00:13:47,530 --> 00:13:51,460 And we'll set this to 0.45 seconds as default. 213 00:13:51,460 --> 00:13:56,680 And we're also going to want to make a reference to the sound that's inside of the body of our Squidward, 214 00:13:56,680 --> 00:14:00,970 so we could call this footstep sound, and that's inside of our body. 215 00:14:00,970 --> 00:14:02,650 And there's a sound in there called footstep. 216 00:14:03,810 --> 00:14:04,470 Inside of here. 217 00:14:04,470 --> 00:14:06,810 We're also going to want to create another function. 218 00:14:06,810 --> 00:14:09,090 And I'm going to call this function check movement. 219 00:14:09,090 --> 00:14:11,310 And this is to check whether or not our Squidward is moving. 220 00:14:11,310 --> 00:14:15,330 And we only want to play footsteps when he's, you know, moving around. 221 00:14:15,690 --> 00:14:19,500 Then inside of here, what we could do is we could spawn a while loop and a new thread so we could use 222 00:14:19,500 --> 00:14:25,440 tasks dot defer to spawn a new function, and basically we'll have a while true do loop in here. 223 00:14:25,440 --> 00:14:28,590 And what this does is it'll check whether or not our Squidward is moving. 224 00:14:28,590 --> 00:14:31,710 And if our Squidward is moving, then he'll play a footstep. 225 00:14:31,710 --> 00:14:36,030 So while true, do if we call our check movement function. 226 00:14:36,030 --> 00:14:41,940 If that value returned is true, then what we would do is we would just play our footsteps sound. 227 00:14:42,300 --> 00:14:44,760 Now to add some variety to our footsteps sound. 228 00:14:44,760 --> 00:14:48,750 There's actually a pitch shift in there, a sound effect. 229 00:14:48,750 --> 00:14:53,400 So inside of the footsteps sound there is a pitch shift sound effect. 230 00:14:53,400 --> 00:14:59,250 And we can change the octave of the sound effect and use our RNG next number. 231 00:14:59,250 --> 00:15:03,480 And we could pass a value between anywhere between 0.9 and 1.1. 232 00:15:03,480 --> 00:15:04,980 The default is one. 233 00:15:05,550 --> 00:15:10,770 So if we go to our handsome Squidward AI and inside of the body, here's our footsteps sound with a 234 00:15:10,770 --> 00:15:12,420 default pitch of one. 235 00:15:12,420 --> 00:15:14,490 Our Squidward footsteps sounds like this. 236 00:15:15,220 --> 00:15:22,180 But if we, you know, reduced the octave by like 0.9 and we play it now, then it sounds a little bit 237 00:15:22,180 --> 00:15:24,550 deeper and then we can also increase it. 238 00:15:26,510 --> 00:15:27,140 That way. 239 00:15:27,140 --> 00:15:30,320 You know, footsteps don't always sound the exact same. 240 00:15:30,320 --> 00:15:37,460 We add a little bit of variety to the pitch of our footstep, so we play that footstep if we're moving. 241 00:15:37,520 --> 00:15:43,520 And then what we would also want to do is we want to refer to our last position and set that equal to 242 00:15:43,520 --> 00:15:45,290 the my root part dot position. 243 00:15:45,290 --> 00:15:47,090 And you'll see why we're doing this in a moment. 244 00:15:47,090 --> 00:15:51,470 Now just in case this footstep sound was already playing before we actually play the footstep sound 245 00:15:51,470 --> 00:15:56,900 again, we also want to make sure to stop our footstep sound, and we also want to make sure that we 246 00:15:56,900 --> 00:16:03,710 actually set our last position before we start this while loop equal to the my root part dot position. 247 00:16:04,220 --> 00:16:10,250 So basically what we're going to do in this check movement function is we're going to get the last material 248 00:16:10,250 --> 00:16:12,140 that our humanoid was standing on. 249 00:16:12,140 --> 00:16:14,720 So we're it's going to be equal to my humanoid. 250 00:16:14,720 --> 00:16:17,150 And there's a property called Floor material. 251 00:16:17,150 --> 00:16:19,460 And we want to make sure that this is in air. 252 00:16:19,490 --> 00:16:19,940 Right. 253 00:16:19,940 --> 00:16:24,740 We don't want to play footstep sounds when our AI, Squidward, is in the air. 254 00:16:24,740 --> 00:16:26,240 That doesn't make any sense, right? 255 00:16:26,240 --> 00:16:29,630 So we want to have an if statement here, and we want to check. 256 00:16:29,630 --> 00:16:33,950 First off, if my humanoid dot walk speed is greater than zero. 257 00:16:34,340 --> 00:16:40,730 And we also want to make sure that my root part dot position, and we want to subtract this by our last 258 00:16:40,730 --> 00:16:46,520 position and get the magnitude between those two positions is greater than or equal to something like 259 00:16:46,520 --> 00:16:47,030 three studs. 260 00:16:47,030 --> 00:16:53,450 So this actually verifies that, you know, we're moving around the map if this is less than three studs 261 00:16:53,450 --> 00:16:58,790 or it's zero studs or whatever, then that signifies that our humanoid is still relatively in the same 262 00:16:58,790 --> 00:16:59,600 position. 263 00:16:59,600 --> 00:17:03,590 And because we know that then our humanoid hasn't actually moved around. 264 00:17:03,590 --> 00:17:07,910 So we're going to, you know, not play a footstep sound. 265 00:17:08,690 --> 00:17:13,610 So if our walk speed is greater than zero and our magnitude is greater than or equal to three studs. 266 00:17:14,220 --> 00:17:20,190 And we also want to make sure that the last material that we were standing on isn't equal to null. 267 00:17:20,190 --> 00:17:25,590 And we also want to make sure that the last material we were standing on is not equal to the enum dot 268 00:17:25,590 --> 00:17:27,360 material, dot air. 269 00:17:27,780 --> 00:17:33,030 If that's the case, then we can go ahead and return true because our walk speed is greater than zero. 270 00:17:33,060 --> 00:17:37,860 We've actually moved and we're actually standing on ground and we're not standing on air. 271 00:17:37,860 --> 00:17:40,080 Or last material isn't equal to nil. 272 00:17:40,080 --> 00:17:42,390 So this signifies that we're actually moving. 273 00:17:42,390 --> 00:17:45,960 And because we're moving then we can go ahead and play footstep sound. 274 00:17:45,960 --> 00:17:51,900 If this isn't the case, then otherwise we can just return false to signify that we're not moving. 275 00:17:51,930 --> 00:17:57,840 Now, another thing we're going to want to keep track of is when the walk speed of our humanoid changes. 276 00:17:57,840 --> 00:18:00,390 And this is because we're going to have two different walk speeds. 277 00:18:00,390 --> 00:18:04,170 We're going to have a walk speed for when our AI is just wandering around the map. 278 00:18:04,170 --> 00:18:06,510 And then we're also going to have a chase speed. 279 00:18:06,510 --> 00:18:09,690 So when our AI sees the player, he starts running towards them. 280 00:18:09,690 --> 00:18:15,150 And when that walk speed changes, then we obviously want to change the cooldown between footsteps in 281 00:18:15,150 --> 00:18:16,020 our while loop. 282 00:18:16,020 --> 00:18:22,590 So after we play a footstep, we'll have a wait, which is our cooldown, which means we're going to 283 00:18:22,590 --> 00:18:26,790 want to listen to when our My Humanoid Get property change signal. 284 00:18:26,790 --> 00:18:30,930 We want to pass the walk speed we want to listen for when this changes. 285 00:18:30,930 --> 00:18:38,280 So for example, if our my humanoid walk speed, let's say it becomes greater than uh, the walk speed 286 00:18:38,280 --> 00:18:39,930 defined within our AI properties. 287 00:18:39,930 --> 00:18:44,400 So if we go in our AI properties, we can have a wandering speed. 288 00:18:45,500 --> 00:18:49,760 And we could also have a chase speed. 289 00:18:50,730 --> 00:18:54,690 So when our eye is chasing a player, this is the walk speed we want to set for them. 290 00:18:54,690 --> 00:18:58,110 When our eye is just wandering around, this is the speed we want to set for them. 291 00:18:58,110 --> 00:19:01,950 So for example, for our wandering speed we could just do like eight studs. 292 00:19:01,950 --> 00:19:03,840 So he's just casually strolling around. 293 00:19:03,840 --> 00:19:08,490 But for our chase speed we could do something like 22 studs per second. 294 00:19:08,790 --> 00:19:12,630 Of course, we want this to be slightly lower than our player sprint speed. 295 00:19:12,630 --> 00:19:15,720 That way our players actually have a chance to run away from our Squidward. 296 00:19:16,500 --> 00:19:22,410 But what we could do is we could check if our humanoids walk, speed becomes greater than our AI properties. 297 00:19:23,280 --> 00:19:24,840 Dot wandering speed. 298 00:19:25,620 --> 00:19:31,260 If that's the case, then we want to set the cooldown value equal to 0.25. 299 00:19:31,260 --> 00:19:33,240 So we reduce that cooldown. 300 00:19:33,570 --> 00:19:39,060 Otherwise, we can just keep the cooldown at the default of 0.45 seconds. 301 00:19:39,600 --> 00:19:43,080 And this should allow us to create audible footsteps for our players. 302 00:19:43,080 --> 00:19:46,440 That way they can actually listen for when our Squidward is nearby. 303 00:19:46,770 --> 00:19:51,780 After this point, since we've set the parent of our I, Squidward equal to the workspace as you saw 304 00:19:51,780 --> 00:19:57,810 earlier, he spawns up here and we need to actually go ahead and move him at to one of those spawn points 305 00:19:57,810 --> 00:20:00,420 that are defined within our server storage. 306 00:20:00,630 --> 00:20:06,510 So what we could do is we could create a function and we could call it something like disappear and 307 00:20:06,510 --> 00:20:07,620 spawn a new location. 308 00:20:07,620 --> 00:20:13,560 So we could call this function disappear and spawn at new location. 309 00:20:13,560 --> 00:20:18,840 And we can use this function whenever we want to have our Squidward disappear and have them reappear 310 00:20:18,840 --> 00:20:20,550 at a new spawn location. 311 00:20:20,550 --> 00:20:25,650 So for example, if our wandering iterations go beyond, let's say five, then we can have them disappear 312 00:20:25,650 --> 00:20:28,890 and spawn out a new spawn location and start pathfinding from that point. 313 00:20:29,490 --> 00:20:35,250 So to have them disappear and spawn at a new location, first we want to refer to a particle emitter 314 00:20:35,250 --> 00:20:39,480 that is inside of the body of our Squidward, and we want to emit a crap ton of particles. 315 00:20:39,480 --> 00:20:41,400 We could do something like 300 this way. 316 00:20:41,400 --> 00:20:46,200 It kind of masks him, and it doesn't make it look like you know, he disappeared out of thin air. 317 00:20:46,560 --> 00:20:51,510 So actually, you know, let's just keep our handsome Squidward AI inside of the workspace. 318 00:20:52,990 --> 00:20:55,480 So we'll set his parent equal to the workspace. 319 00:20:55,480 --> 00:20:58,990 We'll go back to them and inside of his body he has a particle emitter. 320 00:20:58,990 --> 00:21:01,270 And we can emit something like 300 particles. 321 00:21:01,270 --> 00:21:06,280 And it kind of helps mask him to make it look like, you know, he disappears. 322 00:21:06,280 --> 00:21:08,830 So after the particles disappear, he's no longer there. 323 00:21:09,340 --> 00:21:13,810 So after we emit a crap ton of particles, there's a sound inside of his body called poof. 324 00:21:14,620 --> 00:21:16,720 And we'll just play that to sound like, you know. 325 00:21:16,720 --> 00:21:17,050 Oh. 326 00:21:17,050 --> 00:21:17,950 He disappeared. 327 00:21:17,950 --> 00:21:23,140 So inside of the body of our Squidward, there's a sound called poof, and we'll just play that sound. 328 00:21:23,710 --> 00:21:27,310 And after we do that, we can wait for, like, one second. 329 00:21:28,810 --> 00:21:33,280 And we could go ahead and have them spawn at a random spawn point. 330 00:21:33,280 --> 00:21:40,960 So we'll get a random int from our RNG next integer, and we're going to do one to the maximum number 331 00:21:40,960 --> 00:21:42,760 of our different spawn points. 332 00:21:43,000 --> 00:21:46,840 And what we could do is we could refer to my root part and set the key frame. 333 00:21:48,290 --> 00:21:50,690 Equal to a random C frame. 334 00:21:50,690 --> 00:21:54,590 So inside of our spawn points table we'll pass our random integer. 335 00:21:55,210 --> 00:21:59,980 And then just get the C frame of the part that's, you know, we randomly chosen. 336 00:22:00,630 --> 00:22:05,280 And after he's at this new spawn location, what we could do is we could refer to our My Humanoid. 337 00:22:05,280 --> 00:22:09,150 And what we want to do is we want to move him to a new position. 338 00:22:09,750 --> 00:22:13,590 And the snoop position we want to move him to is inside of the spawn points. 339 00:22:13,590 --> 00:22:18,840 Pass the random int again, so we refer to the exact same part, because inside of those different spawn 340 00:22:18,840 --> 00:22:25,980 points is we have a attachment inside of them, and this attachment is called walk to point. 341 00:22:26,540 --> 00:22:32,780 And we can get the world, see frame of that attachment and get the position that we want him to walk 342 00:22:32,780 --> 00:22:33,290 to. 343 00:22:33,620 --> 00:22:37,940 So if we go inside of server storage. 344 00:22:38,630 --> 00:22:40,730 Here we go to Squidward spawns. 345 00:22:40,880 --> 00:22:42,140 We have different walk. 346 00:22:42,140 --> 00:22:42,680 Two points. 347 00:22:42,680 --> 00:22:49,100 So for example, here's one where he spawns up here, goes to the ceiling and walks down, or basically 348 00:22:49,100 --> 00:22:52,970 falls through this hole in the ceiling to this position here. 349 00:22:53,510 --> 00:22:58,610 And that way he can actually, you know, get inside of the map and start pathfinding around the place. 350 00:22:59,360 --> 00:23:01,880 So we'll move him to this position. 351 00:23:02,180 --> 00:23:06,890 And then what we want to do is we want to wait for him to finish moving to this position. 352 00:23:06,890 --> 00:23:12,500 So that means we're going to want to wait for the move to finish event inside of our My Humanoid. 353 00:23:12,830 --> 00:23:17,600 And in order to do that, what we could do is we could go to our game sections module script, and we 354 00:23:17,600 --> 00:23:22,820 can scroll up and we can go ahead and just copy our wait for event function that we did before. 355 00:23:23,150 --> 00:23:26,900 And we could go ahead and put that inside of here. 356 00:23:28,870 --> 00:23:31,480 And we can go ahead and wait for event. 357 00:23:31,480 --> 00:23:34,540 My humanoid move to finish. 358 00:23:35,220 --> 00:23:40,830 And we can have a timeout of like three seconds, and then we can check whether or not we timed out. 359 00:23:42,030 --> 00:23:47,190 So if we timed out, then obviously we ran into a little bit of a problem. 360 00:23:47,190 --> 00:23:53,340 So what we'll have to do instead is we'll just have to make him disappear and then reappear at this 361 00:23:53,340 --> 00:23:56,280 point that we tried to walk him to because he couldn't walk there. 362 00:23:56,280 --> 00:23:58,410 So we'll just have to teleport him there instead. 363 00:23:58,410 --> 00:24:04,020 So what we could do is we could refer to the body dot particle emitter and emit something like another 364 00:24:04,020 --> 00:24:05,460 300 particles. 365 00:24:07,740 --> 00:24:12,600 And then we can play the poof sound in our body again, so body poof will play the sound. 366 00:24:12,960 --> 00:24:18,480 We can wait something like one second to just give enough time for the particles to spread out, and 367 00:24:18,480 --> 00:24:22,290 then we'll refer to our my root part dot position. 368 00:24:23,610 --> 00:24:25,950 And we'll set that equal to the spawn points. 369 00:24:25,950 --> 00:24:29,040 And actually we'll just copy what we did exactly right here. 370 00:24:29,950 --> 00:24:32,470 So we'll just set him to that position directly. 371 00:24:32,470 --> 00:24:36,340 And after we do that again, we'll emit some more particles. 372 00:24:36,340 --> 00:24:42,700 So body dot particle emitter emit something like 300 particles. 373 00:24:42,880 --> 00:24:45,250 And we'll play the poof sound again. 374 00:24:45,250 --> 00:24:47,770 So body dot poof play. 375 00:24:48,990 --> 00:24:53,160 And then after this point, we can go ahead and put a wait statement down here of like one second. 376 00:24:53,160 --> 00:24:56,760 That way our eye doesn't start wandering instantaneously. 377 00:24:56,760 --> 00:25:02,130 So when our eye gets put on the map and he walks to the first point to actually enter into the basement, 378 00:25:02,130 --> 00:25:06,900 we're going to have him sit there for like one second that way, you know, in case he accidentally, 379 00:25:06,900 --> 00:25:11,040 like, falls directly on top of a player, he doesn't kill them instantly because that would be a little 380 00:25:11,040 --> 00:25:11,550 unfair. 381 00:25:12,090 --> 00:25:16,020 So then we can go ahead and call our disappear and spawn a new location function. 382 00:25:16,020 --> 00:25:21,060 So after we set up the footsteps and he's on the map, then we place some inside of the basement and 383 00:25:21,060 --> 00:25:26,670 after this point we can go ahead and start the main loop that will be running our AI. 384 00:25:26,700 --> 00:25:28,650 So we could have a function. 385 00:25:28,650 --> 00:25:30,150 We could call it main. 386 00:25:31,450 --> 00:25:35,080 And this would run forever while our AI is active. 387 00:25:35,080 --> 00:25:40,570 So while active is true, what we would do is we would execute all the functionality for our AI. 388 00:25:40,600 --> 00:25:44,890 So what we could do down here is set active equal to true and then call our main function. 389 00:25:44,890 --> 00:25:47,560 And now our AI is going to be active. 390 00:25:47,920 --> 00:25:52,090 Now when our AI is active the first thing we want to check is whether or not we have a target that we 391 00:25:52,090 --> 00:25:52,960 can attack. 392 00:25:52,960 --> 00:25:54,220 So we can create a variable. 393 00:25:54,220 --> 00:25:55,930 And I'm going to call this target. 394 00:25:56,320 --> 00:26:01,060 And we can have a function to get basically the nearest visible player to our AI. 395 00:26:01,090 --> 00:26:04,870 So we could have a function called get nearest visible player. 396 00:26:04,870 --> 00:26:10,960 And this will return back to us basically a root part of the nearest target that we can attack. 397 00:26:10,960 --> 00:26:17,950 So we can have a function here and we can call this get nearest visible player. 398 00:26:18,930 --> 00:26:23,400 And this will loop through all of the alive players in our game and make sure you know they're not dead, 399 00:26:23,400 --> 00:26:24,570 they're not in a locker. 400 00:26:24,570 --> 00:26:29,370 And it'll also make sure that we can actually see that player and we can actually go and chase them. 401 00:26:29,820 --> 00:26:31,170 I made a little small spelling error. 402 00:26:31,170 --> 00:26:32,400 So let me fix that real quick. 403 00:26:32,400 --> 00:26:33,930 Get nearest visible player. 404 00:26:33,930 --> 00:26:37,290 And after that, what we want to do is we want to create a variable in here. 405 00:26:37,290 --> 00:26:38,850 We'll call it closest. 406 00:26:39,470 --> 00:26:46,220 Target will set this equal to nil for now, and we want a distance to compare the closest target to. 407 00:26:46,250 --> 00:26:48,020 So we could call this last distance. 408 00:26:48,020 --> 00:26:51,740 And by default we're just going to set it to some randomly high number because we don't care. 409 00:26:51,740 --> 00:26:59,150 But basically we want to compare the last target that we found that was close to our eye to the previous 410 00:26:59,150 --> 00:27:00,050 distance. 411 00:27:00,170 --> 00:27:01,940 You may be thinking, what do you mean? 412 00:27:01,940 --> 00:27:04,670 So let's say there's three different players around our eye. 413 00:27:04,700 --> 00:27:09,440 Well, our eye needs to figure out out of those three players which one is the closest. 414 00:27:09,440 --> 00:27:13,190 So it needs to compare the distances between all those different players. 415 00:27:13,190 --> 00:27:17,180 And it basically needs to go through the process of elimination and figure out which player is closest. 416 00:27:17,180 --> 00:27:17,660 Right. 417 00:27:17,660 --> 00:27:21,950 So we'll loop through every single player that is in our alive team. 418 00:27:21,950 --> 00:27:24,110 So we'll get every single player in there. 419 00:27:24,260 --> 00:27:29,510 And we want to do is we want to first make sure that this player is alive and they're not inside of 420 00:27:29,510 --> 00:27:31,640 a locker, or they don't have a character or whatever. 421 00:27:31,850 --> 00:27:34,880 So if this player does not have a character. 422 00:27:36,350 --> 00:27:40,400 Or let's say this player does not have a root part for some reason. 423 00:27:42,930 --> 00:27:48,570 Or let's say this player character humanoid get their health. 424 00:27:48,690 --> 00:27:50,280 Let's say that's below one. 425 00:27:50,280 --> 00:27:52,170 Or basically they're dead, right? 426 00:27:52,170 --> 00:27:55,440 Or let's say this player is inside of the lockers. 427 00:27:55,440 --> 00:28:01,350 So if player get attribute inside lockers true, then we want to ignore this player as well. 428 00:28:01,350 --> 00:28:05,040 Or we also want to make sure that this player hasn't escaped from our game. 429 00:28:05,040 --> 00:28:09,120 Remember we set an attribute on them when they escape the basement of escaped. 430 00:28:09,120 --> 00:28:11,850 So if that's true, we don't want to care about this player either. 431 00:28:12,120 --> 00:28:13,470 So basically. 432 00:28:15,320 --> 00:28:19,400 If this player doesn't have a character or they're dead, or they're in a locker or they've already 433 00:28:19,400 --> 00:28:23,780 escaped, then we just want to continue looping because we don't care about this particular player. 434 00:28:23,810 --> 00:28:29,180 Otherwise, if they pass all this criteria, then we need to check their distance away from our eye. 435 00:28:29,180 --> 00:28:32,720 And we also need to check whether or not they're visible so we can create a variable. 436 00:28:32,720 --> 00:28:34,190 I'm going to call this new target. 437 00:28:34,640 --> 00:28:40,130 And we're not going to initialize anything just yet because we want to first check the visibility of 438 00:28:40,130 --> 00:28:41,720 the root part of this player. 439 00:28:41,720 --> 00:28:43,670 So we could create another function. 440 00:28:44,320 --> 00:28:48,610 And we can call this function something like check visibility. 441 00:28:48,610 --> 00:28:52,900 And we would get passed a target here which would be a base part. 442 00:28:53,800 --> 00:28:56,020 And then we could also have a boolean pass to this. 443 00:28:56,020 --> 00:28:58,300 And I'm going to call this with Dot. 444 00:28:59,040 --> 00:29:03,720 And this is because we're going to use this boolean to determine whether or not we should calculate 445 00:29:03,720 --> 00:29:07,830 this visibility using vector three dot or not. 446 00:29:07,830 --> 00:29:09,750 And you might be thinking what's vector three dot? 447 00:29:09,780 --> 00:29:15,330 Well, if you haven't heard of vector three dot, what it does is it returns a scalar product of two 448 00:29:15,330 --> 00:29:16,290 vector threes. 449 00:29:16,290 --> 00:29:17,400 What does that mean? 450 00:29:17,400 --> 00:29:22,920 Well, if I create a new vector three here let's just do 111 and I use a dot. 451 00:29:22,920 --> 00:29:26,130 It returns a scalar dot product of the two vectors. 452 00:29:26,130 --> 00:29:32,310 So that means you would pass another vector three to this function vector three dot new. 453 00:29:32,310 --> 00:29:36,660 And you could do something like negative one, negative one negative one. 454 00:29:37,190 --> 00:29:42,260 And this function will tell you basically how similar are these two vector threes. 455 00:29:42,290 --> 00:29:44,750 Are they both looking in the same direction or not? 456 00:29:44,750 --> 00:29:50,810 Since these two vector threes are exact opposites, then this function would return a value of negative 457 00:29:50,810 --> 00:29:57,770 one to signify that this vector three is facing the exact opposite direction of this vector three because, 458 00:29:57,770 --> 00:30:03,290 as you know, a vector three is basically just a direction in 3D space starting from the origin point. 459 00:30:03,290 --> 00:30:07,310 So we can go ahead and compare what direction they are facing. 460 00:30:07,700 --> 00:30:13,490 And I'll show you this example right now if I copy this, and I were to print out this value here, 461 00:30:13,490 --> 00:30:19,640 and we actually need to convert this vector three to a normalized copy, or basically a vector three 462 00:30:19,640 --> 00:30:23,450 that has a magnitude or length of one stud. 463 00:30:23,450 --> 00:30:26,330 And we need to do that for both of these vector threes. 464 00:30:26,600 --> 00:30:28,910 And if I print this value out here. 465 00:30:30,330 --> 00:30:33,360 It's like I got a little bit of an error if I print this out. 466 00:30:33,360 --> 00:30:33,990 There we go. 467 00:30:34,020 --> 00:30:36,450 We basically get a value of negative one. 468 00:30:36,450 --> 00:30:42,360 And this is telling us that, hey, these two vector threes are facing the exact opposite direction. 469 00:30:43,150 --> 00:30:48,940 If I were to do the exact same vector three, then we're going to get a value of one, which signifies 470 00:30:48,940 --> 00:30:52,630 that these two vector threes are facing the exact same direction. 471 00:30:53,110 --> 00:30:55,600 And you might be thinking, well, what's the purpose of this? 472 00:30:55,630 --> 00:31:01,810 Well, the usefulness of this function is we can determine whether or not a player is within the field 473 00:31:01,810 --> 00:31:06,550 of view, or basically the pseudo field of view of our eye. 474 00:31:06,580 --> 00:31:07,090 Right. 475 00:31:07,090 --> 00:31:13,450 We can determine or we can set a threshold for when our eye can no longer see any players. 476 00:31:14,240 --> 00:31:17,510 So to explain this more easily, I'll give an example here. 477 00:31:17,510 --> 00:31:22,160 Let's just say this is the head of my eye and this is the direction that he's facing. 478 00:31:22,160 --> 00:31:22,790 Right. 479 00:31:22,880 --> 00:31:24,530 We can get this direction. 480 00:31:24,530 --> 00:31:26,300 And let's just say it has a length of one. 481 00:31:26,300 --> 00:31:30,140 And then let's say we also have another player on our map, like over here. 482 00:31:30,410 --> 00:31:36,290 What we're going to do is we're going to basically get the direction from our head to this player. 483 00:31:36,290 --> 00:31:37,940 So we would calculate. 484 00:31:38,560 --> 00:31:39,460 That direction. 485 00:31:39,460 --> 00:31:39,940 Right. 486 00:31:39,940 --> 00:31:45,220 And then we would compare this vector three to the vector three of where our eye is facing. 487 00:31:45,220 --> 00:31:47,110 And we would check the difference. 488 00:31:47,140 --> 00:31:52,450 Now because these two vectors would be basically facing the opposite directions, we would know that 489 00:31:52,450 --> 00:31:55,930 this player right here is not within the field of view of our eye. 490 00:31:55,930 --> 00:32:02,050 But let's say we had a player over here and then we calculated the direction to this player. 491 00:32:02,110 --> 00:32:06,070 Well, then we would figure out, hey, these two vector threes are pretty similar. 492 00:32:06,070 --> 00:32:06,910 We could set a threshold. 493 00:32:06,910 --> 00:32:10,060 Maybe the value of this is like 0.5. 494 00:32:10,910 --> 00:32:17,300 The, uh, a value or basically a vector three that would be perpendicular to this would be zero. 495 00:32:17,300 --> 00:32:21,560 And a direction that's exactly opposite would be negative one. 496 00:32:22,220 --> 00:32:24,470 So we could set a threshold of like 0.2. 497 00:32:24,500 --> 00:32:31,420 So that way when we calculate the dot product of these vector threes, so any that fall between 1 and 498 00:32:31,420 --> 00:32:35,450 0.2 means that they're basically within the field of view. 499 00:32:35,480 --> 00:32:39,080 You can imagine this imaginary field of view of our eye. 500 00:32:39,230 --> 00:32:42,050 This player right here falls within that field of view. 501 00:32:42,050 --> 00:32:45,620 And because they do that means our eye can go and attack them. 502 00:32:46,190 --> 00:32:49,640 And that's the power that we can use with the dot function. 503 00:32:50,990 --> 00:32:55,130 So inside of this function, what we could do is we could check if width dot is true. 504 00:32:55,130 --> 00:32:57,080 If it is, then we need to calculate it. 505 00:32:57,080 --> 00:32:59,990 So what we're going to do is we're going to make several variables. 506 00:32:59,990 --> 00:33:04,520 One variable I'm going to make is called uh direction to target. 507 00:33:04,520 --> 00:33:11,240 And this is the vector three starting at our eyes head aiming towards the target that we want to look 508 00:33:11,240 --> 00:33:11,630 at. 509 00:33:11,630 --> 00:33:15,950 So basically what we would do is we would get the target's position. 510 00:33:16,710 --> 00:33:22,380 And subtract it by the origin point, we would want to have this direction start at, which would be 511 00:33:22,380 --> 00:33:24,540 our my root part dot position. 512 00:33:24,810 --> 00:33:29,130 And we want to get the unit or normalized copy of this vector three. 513 00:33:29,130 --> 00:33:35,610 So now that we have this direction that's towards our target starting at our root part, we want to 514 00:33:35,610 --> 00:33:38,970 compare this with the look direction of our root part. 515 00:33:39,510 --> 00:33:43,110 So what we could do is we could create a variable I'm going to call this look direction. 516 00:33:43,110 --> 00:33:47,220 And this is just going to be equal to my root part dot c frame. 517 00:33:47,220 --> 00:33:49,620 And we get the look vector of that c frame. 518 00:33:49,710 --> 00:33:53,400 So here we have our root part and the direction that it's facing. 519 00:33:53,400 --> 00:33:56,730 And here we have this other direction that's towards our target. 520 00:33:56,730 --> 00:34:01,650 And we want to compare these two directions to see how similar or unsimilar these two directions are. 521 00:34:01,650 --> 00:34:04,110 So we can get the dot product. 522 00:34:05,340 --> 00:34:11,340 By referring to our direction to the target and using the dot function, and we could pass our look 523 00:34:11,340 --> 00:34:18,480 direction, and this will return a value to us of, you know, how similar are these two vector threes. 524 00:34:18,540 --> 00:34:24,030 And basically what we could do is we could have a property inside of our self table here. 525 00:34:24,030 --> 00:34:28,020 And we can call this property something like minimum dot product. 526 00:34:28,020 --> 00:34:31,140 And I'm going to set this to something like 0.1. 527 00:34:31,320 --> 00:34:35,370 So basically our eye will have a pretty wide field of view. 528 00:34:35,370 --> 00:34:43,080 But basically any players that are I guess within this kind of field of view of our eye is going to 529 00:34:43,080 --> 00:34:44,940 be seen and attacked. 530 00:34:44,940 --> 00:34:49,290 So you can imagine this direction here and this direction here. 531 00:34:49,290 --> 00:34:51,510 This is where our eye is facing. 532 00:34:51,630 --> 00:34:54,990 Comparing this direction to this direction is a value of zero. 533 00:34:54,990 --> 00:34:59,220 And the value of 0.1 would be like something over here. 534 00:34:59,220 --> 00:35:02,430 So basically he has a pretty wide stinking field of view. 535 00:35:02,430 --> 00:35:06,840 Of course you could adjust that number to whatever you like, but this should work pretty well for what 536 00:35:06,840 --> 00:35:07,620 we're doing. 537 00:35:08,580 --> 00:35:13,290 So we can go ahead and check to see if our dot product is less than our I. 538 00:35:13,320 --> 00:35:16,110 Properties dot minimum dot product. 539 00:35:16,110 --> 00:35:22,530 If it is, then this player is not in the field of view of our I and we're just going to return false. 540 00:35:22,560 --> 00:35:28,230 Otherwise that means we have successfully passed the dot calculation. 541 00:35:28,440 --> 00:35:36,180 Now another thing I actually want to do real quick is I want to basically restrict this direction to 542 00:35:36,180 --> 00:35:42,330 the x and z axis and not the y axis, because let's say our player is high up or high down, right? 543 00:35:42,330 --> 00:35:49,920 If our player is super low down or player is super high up, then that's obviously going to affect our 544 00:35:49,920 --> 00:35:50,670 dot product. 545 00:35:50,670 --> 00:35:56,820 But I only want to compare the player's position on their x and z axis. 546 00:35:57,000 --> 00:36:00,990 So what I could do is I'll create a new direction. 547 00:36:02,270 --> 00:36:04,310 And is going to be equal to a vector three dot new. 548 00:36:04,310 --> 00:36:08,180 And all we're going to do is get the direction to our target on the x axis. 549 00:36:08,180 --> 00:36:15,020 We're going to ignore the y axis and then get direction to the target on the z axis, and get a normalized 550 00:36:15,020 --> 00:36:17,450 copy of that direction. 551 00:36:17,960 --> 00:36:24,770 So basically I want to ignore any direction in the y axis because I don't care about the altitude of 552 00:36:24,770 --> 00:36:25,430 our player. 553 00:36:25,430 --> 00:36:32,180 I just want to make sure that our player is within the field of view of our eye on the x and z axis, 554 00:36:32,180 --> 00:36:37,130 and then we can use this new direction instead for the calculation of our dot product. 555 00:36:37,130 --> 00:36:39,590 So we could do new direction. 556 00:36:40,130 --> 00:36:45,410 Dot and compare it to the look direction, and this will give us a pretty accurate dot product. 557 00:36:45,740 --> 00:36:51,230 If we surpass the dot product, meaning the player is within the field of view of our eye, then the 558 00:36:51,230 --> 00:36:57,920 next thing we want to make sure is our eye can actually see them by firing a ray from our eyes eyeballs 559 00:36:57,920 --> 00:37:00,020 to see if it hits that player. 560 00:37:00,350 --> 00:37:03,950 So I'm going to do is I'm going to create a parameters for a new raycast. 561 00:37:03,950 --> 00:37:06,560 So raycast params dot new. 562 00:37:07,040 --> 00:37:09,830 By this point you should be quite familiar with Raycasting. 563 00:37:09,830 --> 00:37:14,000 But if you aren't familiar with Raycasting, well, it's pretty simple. 564 00:37:14,000 --> 00:37:20,900 We create parameters for our raycast and inside of this parameters we can filter out specific instances 565 00:37:20,900 --> 00:37:27,020 that we want to ignore, and in this case, the different instances that we want to ignore is basically 566 00:37:27,020 --> 00:37:28,070 everything within our eye. 567 00:37:28,100 --> 00:37:28,760 Squidward. 568 00:37:28,760 --> 00:37:34,700 So that way we don't want the ray to hit any part in our Squidward, and we also want the ray to ignore 569 00:37:34,700 --> 00:37:36,740 any part that is inside of the workspace. 570 00:37:36,740 --> 00:37:40,880 That filtering folder which stores all of the invisible parts in the workspace. 571 00:37:41,300 --> 00:37:44,180 And then we can set the params dot filter type. 572 00:37:44,820 --> 00:37:52,110 Equal to the enum dot raycast filter type, and we want to exclude these different instances. 573 00:37:52,110 --> 00:37:55,800 So that way our raycast ignores them and the ray goes directly through them. 574 00:37:55,800 --> 00:37:59,760 And then from this point we can calculate the direction for this raycast. 575 00:38:00,060 --> 00:38:03,630 And that's going to be where we get our target. 576 00:38:03,630 --> 00:38:05,460 And we're going to get their position. 577 00:38:06,000 --> 00:38:09,540 And the origin point for this array is going to be our eyeballs. 578 00:38:09,540 --> 00:38:13,290 So inside of the eyes of our Squidward, we have that raycast part. 579 00:38:14,030 --> 00:38:15,800 And we want to get the position of that. 580 00:38:15,920 --> 00:38:19,430 And then we also want to get a normalized copy of this direction. 581 00:38:19,430 --> 00:38:21,350 So that way it's only one stud. 582 00:38:21,650 --> 00:38:27,650 And then from this point we can multiply it by some number to independently control how long we want 583 00:38:27,650 --> 00:38:28,790 this direction to be. 584 00:38:28,790 --> 00:38:32,540 So from this point we can use the workspace raycast function. 585 00:38:33,530 --> 00:38:41,180 And the origin for this raycast is going to be the eyes dot raycast part dot position and our direction 586 00:38:41,180 --> 00:38:43,610 is going to be equal to the direction we just calculated. 587 00:38:43,610 --> 00:38:50,180 And we can multiply this by a distance that we can define inside of our properties table. 588 00:38:50,720 --> 00:38:57,020 So inside of our properties table we could create another property like we could call it targeting distance. 589 00:38:57,530 --> 00:39:04,160 And this will determine in studs how far away our eye can see and target. 590 00:39:04,160 --> 00:39:05,330 You know a player. 591 00:39:05,420 --> 00:39:07,250 And we could do 150 studs. 592 00:39:07,250 --> 00:39:08,930 That'll probably be fine. 593 00:39:09,020 --> 00:39:13,190 So we'll multiply this by our eye properties dot targeting distance. 594 00:39:14,250 --> 00:39:19,170 And the last thing we want to pass to the raycast function is our raycast parameters that we just created. 595 00:39:19,170 --> 00:39:20,340 So params. 596 00:39:20,550 --> 00:39:24,240 And this function will return to us a result. 597 00:39:25,210 --> 00:39:27,220 And we can check to see if we hit anything. 598 00:39:27,220 --> 00:39:34,870 So if we did hit something, if there was a result, and we want to check the instance of the thing 599 00:39:34,870 --> 00:39:35,320 that we hit. 600 00:39:35,320 --> 00:39:38,860 So this will tell us the base part or terrain cell that the ray intersected. 601 00:39:38,860 --> 00:39:47,530 So if this instance is a descendant of so there's a function called is descendant of and we pass our 602 00:39:47,530 --> 00:39:49,300 target dot parent. 603 00:39:49,300 --> 00:39:55,120 So basically since our target is the root part of the player, that means the parent of that root part 604 00:39:55,120 --> 00:39:56,860 is going to be the player's character. 605 00:39:56,860 --> 00:40:02,230 So if the instance that we hit is a child or descendant of the player's character, then that means 606 00:40:02,230 --> 00:40:03,790 we hit the right target. 607 00:40:04,300 --> 00:40:13,000 The next thing we want to check is if the target dot position on the y axis is less than or equal to 608 00:40:13,000 --> 00:40:17,920 the, uh, position of our root part on the y axis. 609 00:40:17,980 --> 00:40:19,390 And why do we want to check this? 610 00:40:19,420 --> 00:40:26,770 Well, this will tell us if our player is for some reason below our, uh, I if that's the case, then 611 00:40:26,770 --> 00:40:27,280 that's great. 612 00:40:27,280 --> 00:40:30,610 Our I can go ahead and get to the player and we can return true here. 613 00:40:31,210 --> 00:40:32,440 However. 614 00:40:33,150 --> 00:40:39,330 Let's say for some reason, uh, somehow our player is super high up there, like standing on, like 615 00:40:39,330 --> 00:40:40,440 a building or something. 616 00:40:40,470 --> 00:40:44,760 Of course, this is code you could use for different AI later on, and that's why we're making this 617 00:40:44,760 --> 00:40:45,540 check real quick. 618 00:40:45,540 --> 00:40:51,540 But if this player is like way too high up, then our AI is not going to be able to pathfind to this 619 00:40:51,540 --> 00:40:51,840 player. 620 00:40:51,840 --> 00:40:53,520 And we want to ignore this player. 621 00:40:53,520 --> 00:41:01,470 So we want to do is we want to basically, uh, get our target dot position. 622 00:41:02,270 --> 00:41:09,830 On the y axis and subtract this by my root part dot position on the y axis. 623 00:41:09,830 --> 00:41:12,560 And we just want to get the absolute value of this. 624 00:41:12,560 --> 00:41:14,630 So math dot absolute. 625 00:41:15,160 --> 00:41:20,230 And we want to basically compare this to a number that we can define in our properties as well. 626 00:41:20,230 --> 00:41:26,110 So inside of our properties we could create a property like max visibility height. 627 00:41:26,110 --> 00:41:32,590 And this will define in studs how high up a player can be or the maximum height that they can be where 628 00:41:32,590 --> 00:41:34,990 our uh where our eye can get to them. 629 00:41:34,990 --> 00:41:36,970 And I found eight studs to be good. 630 00:41:36,970 --> 00:41:43,630 When a player gets above eight studs in height above the root part of our Squidward, then we'll start 631 00:41:43,630 --> 00:41:47,770 running into some problems because our AI can't properly pathfind to that player. 632 00:41:47,770 --> 00:41:48,820 They're too high up. 633 00:41:49,240 --> 00:41:54,730 So for some reason, the position of our target is greater than our AI properties. 634 00:41:54,730 --> 00:41:56,410 Dot max visibility height. 635 00:41:56,410 --> 00:41:59,410 Then we're just going to return false because we don't care about this player. 636 00:41:59,410 --> 00:42:01,960 They're too high up otherwise. 637 00:42:01,960 --> 00:42:06,940 In any other case, we're just going to return true because we are good to go. 638 00:42:07,360 --> 00:42:14,020 However, if we did not get a result from our raycast then we are going to return false meaning this 639 00:42:14,020 --> 00:42:16,090 player could be behind a wall. 640 00:42:16,090 --> 00:42:17,770 Maybe they're hiding behind something. 641 00:42:17,770 --> 00:42:22,930 Whatever the case may be, our AI does not see this particular player, so we're going to return false. 642 00:42:23,930 --> 00:42:26,450 The back and side of our get nearest visible player function. 643 00:42:26,450 --> 00:42:34,550 What we can do is we can check the visibility for our player character, that humanoid root part. 644 00:42:35,270 --> 00:42:40,460 And we want to check with the dot product to make sure that they're in the field of view of our eye. 645 00:42:41,260 --> 00:42:43,270 So we're checking the visibility of this player. 646 00:42:43,270 --> 00:42:45,640 If this is true, they are visible. 647 00:42:45,640 --> 00:42:50,410 Then we can set new target equal to the player character. 648 00:42:51,800 --> 00:42:53,750 That humanoid route part. 649 00:42:55,170 --> 00:42:56,430 Otherwise. 650 00:42:56,880 --> 00:43:05,760 Another thing I want to check for is let's say, um, our player is like really close to our AI. 651 00:43:06,090 --> 00:43:11,190 So, for example, let's say the AI is not facing them, but the player is following really close behind 652 00:43:11,190 --> 00:43:11,460 them. 653 00:43:11,460 --> 00:43:13,860 Well, I don't want players to be able to do that. 654 00:43:13,860 --> 00:43:21,180 If a player gets too close to our AI, I want our AI to start chasing them, no matter if they're behind 655 00:43:21,180 --> 00:43:23,070 them or in front of the AI. 656 00:43:23,100 --> 00:43:24,690 It doesn't matter if they're in the field of view. 657 00:43:24,690 --> 00:43:30,060 So what we could do is we could check if the player dot character dot humanoid. 658 00:43:31,260 --> 00:43:32,370 Route part. 659 00:43:33,340 --> 00:43:36,550 That position subtracted by my route. 660 00:43:36,550 --> 00:43:40,840 Part dot position dot magnitude. 661 00:43:41,880 --> 00:43:49,650 We want to check if this is, uh, less than or equal to a another value that we can define within our 662 00:43:49,650 --> 00:43:50,820 properties table. 663 00:43:51,300 --> 00:43:53,400 So we could create another key in here. 664 00:43:53,400 --> 00:43:56,040 We could call it something like sensing range. 665 00:43:58,610 --> 00:44:06,080 And this will define in studs basically, uh, how far away or how close a player can be sensed by our 666 00:44:06,080 --> 00:44:12,290 AI without our AI even having to, you know, have the player in the field of view, right? 667 00:44:12,320 --> 00:44:14,720 And I found 20 studs to be pretty good. 668 00:44:15,080 --> 00:44:21,560 So if our player is like walking or falling behind our AI, if they get too close, then our AI is going 669 00:44:21,560 --> 00:44:26,660 to sense that they're there and our AI is going to flip around and start chasing that player. 670 00:44:27,410 --> 00:44:32,840 So if the magnitude between, um, these two different positions. 671 00:44:32,840 --> 00:44:35,990 So actually let me readjust that. 672 00:44:35,990 --> 00:44:40,070 So we get the magnitude between these two different positions. 673 00:44:40,070 --> 00:44:49,160 If that is less than or equal to the AI properties dot sensing range, then we can go ahead and set 674 00:44:49,160 --> 00:44:54,650 new target equal to the player character. 675 00:44:56,190 --> 00:44:57,810 That humanoid route part. 676 00:44:57,840 --> 00:45:03,570 Now, another thing we want to make sure of is that our AI can still see the player using the raycast, 677 00:45:03,570 --> 00:45:10,260 because this is only checking whether or not the player is within 20 studs of our AI, and our AI might 678 00:45:10,260 --> 00:45:14,820 be walking down a hallway, and our player might be on another side of the wall, but since they might 679 00:45:14,820 --> 00:45:20,670 be within 20 studs of our AI, our AI tries to attack them, which wouldn't make any sense, right? 680 00:45:20,670 --> 00:45:25,530 So another thing we want to make sure of is that this player is actually still visible. 681 00:45:25,530 --> 00:45:29,310 So we could pass player dot character dot humanoid Rupert. 682 00:45:29,310 --> 00:45:33,300 But this time we don't want to calculate using the vector three dot product. 683 00:45:33,300 --> 00:45:34,650 So we'll pass false here. 684 00:45:34,650 --> 00:45:41,640 So this will simply calculate whether or not this player is visible by firing a ray from our AI's, 685 00:45:41,640 --> 00:45:45,300 you know, eyes to the root part of our player. 686 00:45:46,340 --> 00:45:50,840 So if that checks out, then we can set our new target equal to this root part. 687 00:45:50,960 --> 00:45:57,140 Otherwise, if nothing checks out at all, then we can go ahead and loop to the next player. 688 00:45:58,350 --> 00:45:58,740 Otherwise. 689 00:45:58,740 --> 00:46:05,430 At this point, if we do have a new target, then what we want to do is we want to check the distance 690 00:46:05,430 --> 00:46:09,030 between, um, uh, our A's root part. 691 00:46:09,030 --> 00:46:14,220 So my root part dot position subtracted by a new target dot position. 692 00:46:14,400 --> 00:46:16,260 Get the magnitude of that. 693 00:46:17,510 --> 00:46:20,180 And we want to check if this distance. 694 00:46:21,640 --> 00:46:26,500 Is less than or equal to our targeting distance, which we shouldn't have an issue with that. 695 00:46:26,500 --> 00:46:30,550 So this is just an extra check just in case. 696 00:46:30,820 --> 00:46:37,300 And we also want to make sure that this distance is less than the last distance that we stored up here. 697 00:46:37,970 --> 00:46:40,730 Because we're going to be looping through multiple different players. 698 00:46:40,730 --> 00:46:44,660 We don't want to pick any old player that's visible and close to our eye. 699 00:46:44,690 --> 00:46:50,270 We want to pick the single player that is the closest to our eye. 700 00:46:50,300 --> 00:46:51,830 Out of all the players on our map. 701 00:46:51,830 --> 00:46:58,040 So we want to set closest target equal to this new target, and we also want to set the last distance 702 00:46:58,040 --> 00:47:00,140 equal to this new distance that we calculated. 703 00:47:00,140 --> 00:47:03,020 So we're constantly updating the last distance here. 704 00:47:03,500 --> 00:47:11,000 That way we're guaranteeing that this closest target variable is actually the closest target to our 705 00:47:11,000 --> 00:47:11,720 eye. 706 00:47:11,780 --> 00:47:16,430 After we loop through all the players and we get our closest target, we can go ahead and return it 707 00:47:16,430 --> 00:47:18,050 at the end of this function here. 708 00:47:18,960 --> 00:47:24,300 And then from this point, we can go back down to our main function and we are able to get the closest 709 00:47:24,300 --> 00:47:27,510 target to our eye. 710 00:47:28,210 --> 00:47:33,160 And from this point, if we have a target, then this is where we would start to chase them. 711 00:47:35,040 --> 00:47:41,490 Otherwise, if we don't have a target, then this is where, you know we would wander the map. 712 00:47:41,980 --> 00:47:44,110 Now, of course, this lecture is getting a little long. 713 00:47:44,110 --> 00:47:47,950 So we're going to go ahead and finish scripting up our AI in the next lecture. 714 00:47:47,950 --> 00:47:49,180 I'll go ahead and see you there.